package com.yy.tech.data.logger.mapper;

import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
import com.yy.tech.data.annotation.SecretProperty;
import com.yy.tech.data.logger.context.SecretRuleManager;
import org.springframework.util.StringUtils;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author yy
 * @date 2022/5/13
 * @description: TODO
 */
public class MapperAnnotationIntrospector extends JacksonAnnotationIntrospector {

    @Override
    public Object findSerializationConverter(final Annotated annotated) {
        if (isSecret(annotated)){
            return SecretRuleManager.getManager().findEncoder();
        }
        return super.findSerializationConverter(annotated);
    }


    private boolean isSecret(final Annotated annotated) {
        final AnnotatedElement element = annotated.getAnnotated();
        if (element.isAnnotationPresent(SecretProperty.class)) {
            return true;
        }
        final Field field = getPropertyField(element);
        if (null != field) {
            SecretProperty property =field.getAnnotation(SecretProperty.class);
            if (null != property){
                return true;
            }
            return SecretRuleManager.getManager().match(field.getName());
        }
        return false;
    }

    private Field getPropertyField(final AnnotatedElement element) {
        if (element instanceof Method) {
            final Class<?> cls = ((Method) element).getDeclaringClass();
            final String name = getPropertyName(element);
            Field field = null;
            try {
                field = cls.getDeclaredField(name);
            } catch (final Exception e) {
//                logger.warn(String.format("Not found field[%s] from class [%s]", name, cls.getName()));
            }
            return field;
        }
        return null;
    }

    private String getPropertyName(final AnnotatedElement element) {
        final String methodName = ((Method) element).getName();
        int index = 0;
        index = methodName.startsWith("is") ? 2 : index;
        index = methodName.startsWith("get") ? 3 : index;
        index = methodName.startsWith("set") ? 3 : index;
        final String fieldName = methodName.substring(index);
        return StringUtils.uncapitalize(fieldName);
    }
}
